/*
 * Serdes.h
 *
 *  Created on: Oct 14, 2018
 *      Author: ax
 */

#ifndef INCLUDE_HW_SERDES_H_
#define INCLUDE_HW_SERDES_H_

#include <Type.h>


//XXX STS ordered
typedef enum {
    Serdes_SRIO = 0,/* Srio */
    Serdes_SGMII,   /* Ethernet */
    Serdes_PCIE,    /* PCIE use special lane configuration */
    Serdes_VUSR,    /* Hyper link */
    Serdes_USED,    /* XXX use above only */
    Serdes_DFE,
    Serdes_MAX
} Serdes;

typedef enum {
    Serdes_NO_LOCK = 0,
    Serdes_LOCKED = 1
} Serdes_Status;


//mark enable & master lanes
typedef Bits16 LaneMask;

typedef enum {
    Serdes_LANE_A = 0,
    Serdes_LANE_B,
    Serdes_LANE_C,
    Serdes_LANE_D,
    Serdes_LANE_MAX,
    Serdes_LANE_INVALID
} Serdes_Lane;

typedef enum {
    Serdes_BPS_INVALID      = 0,
    Serdes_12p5G_BPS_KVAL   = 12500000,
    Serdes_6p25G_BPS_KVAL   = 6250000,
    Serdes_5p0G_BPS_KVAL    = 5000000,
    Serdes_3p125G_BPS_KVAL  = 3125000,
    Serdes_2p5G_BPS_KVAL    = 2500000,
    Serdes_2p17G_BPS_KVAL   = 2170000,
    Serdes_1p5625G_BPS_KVAL = 1562500,
    Serdes_1p25G_BPS_KVAL   = 1250000,

    Serdes_INVALID_REF_CLK  = 0,
    Serdes_156p25M_REF_CLK  = 156250,
    Serdes_312p5M_REF_CLK   = 312500
} Serdes_Const;

/** Use this symbol to specify the  link rate */
typedef enum {
    Serdes_LINK_RATE_x4 = 0,
    Serdes_LINK_RATE_x2,
    Serdes_LINK_RATE_x1,
    Serdes_LINK_RATE_div2,

    SGMII_Serdes_LINK_RATE_x2 = 0,
    SGMII_Serdes_LINK_RATE_x1,
    SGMII_Serdes_LINK_RATE_div2,
    SGMII_Serdes_LINK_RATE_div16
} SerdesLinkRate;

/** Use this symbol to specify the Serdes Rx termination **/
typedef enum {
    /** This configuration is for DC coupled systems using CML transmitters*/
    Serdes_RX_TERM_COMMON_POINT_VDDT = 0,
    /** This configuration is for AC coupled systems. The transmitter has no effect on the receiver common mode*/
    Serdes_RX_TERM_COMMON_POINT_AC_COUPLE = 1,
    /** This configuration is for DC coupled systems which require the common mode voltage to be determined by the transmitter only.*/
    Serdes_RX_TERM_COMMON_POINT_FLOATING = 3,
    /** must be 4 for SGMII */
    Serdes_RX_TERM_SGMII_SPECIFIED = 4
} SerdesRxTerm;

/** Use this symbol to specify the Sd Rx adaptive equalizer **/
typedef enum {
    /** Selects the maximum gain, no equalizer */
    Serdes_RX_EQ_MAXIMUM = 0,
    /** Selects the adaptive Receiver equalizer*/
    Serdes_RX_EQ_ADAPTIVE
} SerdesRxEqConfig;

/** Use this symbol to specify the Sd Rx invert polarity **/
typedef enum {
    /** Selects the Receive pair normal polarity*/
    Serdes_RX_NORMAL_POLARITY = 0,
    /** Selects the Receive pair inverted polarity*/
    Serdes_RX_INVERTED_POLARITY
} SerdesRxInvertPolarity;

typedef enum {
    /** No symbol alignment will be performed whilst this setting is selected, or when switching to this selection from another*/
    Serdes_RX_ALIGNMENT_DISABLE = 0,
    /** Symbol alignment will be performed whenever a misaligned comma symbol is received. */
    Serdes_RX_COMMA_ALIGNMENT_ENABLE,
    /** The symbol alignment will be adjusted by one bit position when this mode is selected */
    Serdes_RX_ALIGNMENT_JOG
} SerdesRxAlign;

typedef enum {
    /** Loss of signal detection disabled*/
    Serdes_RX_LOS_DISABLE = 0,
    /** Loss of signal detection enabled. */
    Serdes_RX_LOS_ENABLE = 1,
    /** must set LOS to 4 for non-loopack for hyplnk*/
    Serdes_RX_LOS_VUSR_NON_LOOPBACK_MODE = 4,
} SerdesRxLos;


/** Use this symbol to specify the Sd Tx polarity **/
typedef enum {
    /** Selects Tx pair normal polarity */
    Serdes_TX_NORMAL_POLARITY = 0,
    /** Selects Tx pair inverted polarity */
    Serdes_TX_INVERTED_POLARITY
} SerdesTxInvertPolarity;

typedef enum {
    /** Test mode disabled */
    Serdes_TEST_DISABLED = 0,
    /** Alternating 0/1 Pattern. An alternating 0/1 pattern with a period of 2UI  */
    Serdes_ALTERNATING_0_1,
    /** Generate or Verify 27 . 1 PRBS. Uses a 7-bit LFSR with feedback polynomial x7 + x6 + 1 */
    Serdes_PRBS_7BIT_LFSR,
    /** Generate or Verify 223.1 PRBS. Uses a 23-bit LFSR with feedback polynomial x23 + x18 + 1 */
    Serdes_PRBS_23BIT_LFSR,
    /** Generate or Verify 223.1 PRBS. Uses a 23-bit LFSR with feedback polynomial x23 + x18 + 1 */
    Serdes_PRBS_31BIT_LFSR
} SerdesTestPattern;

/* Use this symbol to specify the Serdes PLL multiply factor */
typedef enum {
    /** Select 4x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_4X = 0x10,
    /** Select 5x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_5X = 0x14,
    /** Select 6x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_6X = 0x18,
    /** Select 8x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_8X = 0x20,
    /** Select 8.25x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_8_25X = 0x21,
    /** Select 10x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_10X = 0x28,
    /** Select 12x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_12X = 0x30,
    /** Select 12.5x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_12_5X = 0x32,
    /** Select 15x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_15X = 0x3C,
    /** Select 16x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_16X = 0x40,
    /** Select 16.5x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_16_5X = 0x42,
    /** Select 20x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_20X = 0x50,
    /** Select 22x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_22X = 0x58,
    /** Select 25x PLL multiply factor */
    Serdes_PLL_MPY_FACTOR_25X = 0x64
} SerdesPllMpyFactor;

/** Use this symbol to specify the Sd PLL voltage range **/
typedef enum {
    Serdes_PLL_VCO_RANGE_LOW = 0,
    Serdes_PLL_VCO_RANGE_HIGH,
    Serdes_PLL_VCO_RANGE_NOT_SPECIFIED
} SerdesVcoRange;

/** Use this symbol to specify the Sd PLL sleep mode **/
typedef enum {
    /** PLL awake  */
    Serdes_PLL_AWAKE = 0,
    /** PLL sleep */
    Serdes_PLL_SLEEP
} SerdesSleepPll;

/** Use this symbol to specify the Sd PLL loop bandwidth **/
typedef enum {
    /** set pll loop bandwidth mid */
    Serdes_PLL_LOOP_BAND_MID = 0,
    /** set pll loop bandwidth ultra high */
    Serdes_PLL_LOOP_BAND_UHIGH,
    /** set pll loop bandwidth low */
    Serdes_PLL_LOOP_BAND_LOW,
    /** set pll loop bandwidth high */
    Serdes_PLL_LOOP_BAND_HIGH
} SerdesLoopBandwidth;

/** Use this symbol to specify the Sd PLL clock bypass **/
typedef enum {
    /* Macro operates normally from the PLL. */
    Serdes_PLL_CLOCK_NO_BYPASS = 0,
    /* The macro operates functionally at low speed using TESTCLKT and TESTCLKR */
    Serdes_PLL_CLOCK_TESTCLK_OBSERVE = 2,
    /* The PLL is bypassed by REFCLKP/N */
    Serdes_PLL_CLOCK_REFCLK_OBSERVE = 3
} SerdesClockBypass;

typedef enum {
    Serdes_LOOPBACK_DISABLE = 0,
    Serdes_LOOPBACK_ENABLE = 3
} SerdesLoopback;

/**
 * @brief This is a sub-structure in @a CSL_AifCommonLinkSetup. This structure is used for
 * configuring the parameters for Serdes params specific to a link  */
typedef struct {
    /*the link speed must be 1x, 2x or 4x of the other link's speed*/
    Uint32              linkSpeed_Kbps;  //not used for SGMII, which is fixed to 1.25G
    SerdesLoopback      loopBack;
    SerdesTestPattern   testPattern;
    /** Output swing. 0~15 represents between 100 and 850 mVdfpp  */
    Uint32              txOutputSwing;
    /** Invert Polarity. Inverts the polarity of TXPi and TXNi. */
    SerdesTxInvertPolarity txInvertPolarity;
    /** Rx loss of Signal */
    SerdesRxLos         rxLos;
    SerdesRxAlign       rxAlign;
    /* Clock/data recovery. Configures the clock/data recovery algorithm */
    Uint8               rxCDR;
    /** polairty of Rx differential i/p - normal/inverted */
    SerdesRxInvertPolarity rxInvertPolarity;
    /** specifies the Rx termination options for AC/DC coupled scenarios */
    SerdesRxTerm        rxTermination;
    /** Rx equalizer configuration */
    SerdesRxEqConfig    rxEqualizerConfig;
}* SerdesLaneCfg, Serdes_LaneConfiguration;

typedef struct {
    Uint32              inputRefClock_KHz;    /*input reference clock in MHz*/
    /** PLL Loop bandwidth setting  */
    SerdesLoopBandwidth loopBandwidth;
    /*follwing parameters are not input parameters,
    they will be drived from other input parameters*/
    Uint32              pllMpy;
    Uint32              serdesPllClock_KHz;
    SerdesVcoRange      vcoRange;
    SerdesLaneCfg       lane[Serdes_LANE_MAX];
}* SerdesCfg, Serdes_Configuration;


typedef struct {
    volatile Uint32 CFGPLL;
    struct {
        volatile Uint32 CFGRX;
        volatile Uint32 CFGTX;
    } LANE[Serdes_LANE_MAX];
} SerdesRegs;


#define Serdes_PLL_CFG_CLKBYP_SHIFT         13
#define Serdes_PLL_CFG_LOOPBANDWIDTH_SHIFT  11
#define Serdes_PLL_CFG_SLEEPPLL_SHIFT       10
#define Serdes_PLL_CFG_VRANGE_SHIFT         9
#define Serdes_PLL_CFG_MPY_SHIFT            1
#define Serdes_PLL_CFG_ENPLL_SHIFT          0

#define Serdes_RX_CFG_TESTPATTERN_SHIFT     25
#define Serdes_RX_CFG_LOOPBACK_SHIFT        23
#define Serdes_RX_CFG_ENOC_SHIFT            22
#define Serdes_RX_CFG_EQ_SHIFT              18
#define Serdes_RX_CFG_CDR_SHIFT             15
#define Serdes_RX_CFG_LOS_SHIFT             12
#define Serdes_RX_CFG_ALIGN_SHIFT           10
#define Serdes_RX_CFG_TERM_SHIFT            7
#define Serdes_RX_CFG_INVPAIR_SHIFT         6
#define Serdes_RX_CFG_RATE_SHIFT            4
#define Serdes_RX_CFG_BUSWIDTH_SHIFT        1
#define Serdes_RX_CFG_ENRX_SHIFT            0

#define Serdes_SGMII_TX_CFG_LOOPBACK_SHIFT  20
#define Serdes_SGMII_TX_CFG_RDTCT_SHIFT     18
#define Serdes_SGMII_TX_CFG_ENIDL_SHIFT     17
#define Serdes_SGMII_TX_CFG_MYSNC_SHIFT     16
#define Serdes_SGMII_TX_CFG_DEMPHASIS_SHIFT 12
#define Serdes_SGMII_TX_CFG_SWING_SHIFT     8
#define Serdes_SGMII_TX_CFG_CM_SHIFT        7

#define Serdes_TX_CFG_TESTPATTERN_SHIFT     23
#define Serdes_TX_CFG_LOOPBACK_SHIFT        21
#define Serdes_TX_CFG_MYSNC_SHIFT           20
#define Serdes_TX_CFG_FIRUPT_SHIFT          19
#define Serdes_TX_CFG_TWPST1_SHIFT          14
#define Serdes_TX_CFG_TWPRE_SHIFT           11
#define Serdes_TX_CFG_SWING_SHIFT           7

#define Serdes_TX_CFG_INVPAIR_SHIFT         6
#define Serdes_TX_CFG_RATE_SHIFT            4
#define Serdes_TX_CFG_BUSWIDTH_SHIFT        1
#define Serdes_TX_CFG_ENTX_SHIFT            0

#define Serdes_PLL_LOCKED_BIT               _BIT(0)

extern
void __init
Serdes_config(
    Serdes      module,
    SerdesCfg   cfg,
    LaneMask    master
);

extern
bool __init
Serdes_isLocked(
    Serdes module
);

#endif /* INCLUDE_HW_SERDES_H_ */
